/*
 * @(#) $Header$
 *
 * Copyright (C) 2010  Daniel Léonard
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package ca.forklabs.crypto.md;

/**
 * This class embodies the algorithm for the message digest Tiger. This
 * imlementation conforms to the reference implementation from
 * <a target="external" href="http://www.cs.technion.ac.il/~biham/">Eli Biham's
 * home page</a>, as does the implementation in
 * <a href="external" href="http://www.gnupg.org">GnuPG</a> and
 * <a href="http://www.cryptix.org">Cryptix</a>. It is more elegant to get an
 * instance with the factory method in class
 * {@link java.security.MessageDigest}:
 * <blockquote>
 * <code>MessageDigest tiger = MessageDigest.getInstance(Forklabs.TIGER, Forklabs.NAME);</code>
 * </blockquote>
 * <!--It is to note that there is a difference between the two authors reference
 * implementation. I chose Mr. Anderson's implementation because it was closer
 * to the description in their paper (which is the same).-->
 *
 * @author   <a href="mailto:forklabs at gmail.com?subject=ca.forklabs.crypto.md.Tiger">Daniel Léonard</a>
 * @version $Revision$
 * @see      ca.forklabs.crypto.Forklabs
 */
public class Tiger extends AbstractBlockMessageDigest {

//---------------------------
// Class variables
//---------------------------

   /** The first S-Box. */
   private static long[] TABLE1 = new long[] {
      0x02aab17cf7e90c5eL   /*    0 */,    0xac424b03e243a8ecL   /*    1 */,
      0x72cd5be30dd5fcd3L   /*    2 */,    0x6d019b93f6f97f3aL   /*    3 */,
      0xcd9978ffd21f9193L   /*    4 */,    0x7573a1c9708029e2L   /*    5 */,
      0xb164326b922a83c3L   /*    6 */,    0x46883eee04915870L   /*    7 */,
      0xeaace3057103ece6L   /*    8 */,    0xc54169b808a3535cL   /*    9 */,
      0x4ce754918ddec47cL   /*   10 */,    0x0aa2f4dfdc0df40cL   /*   11 */,
      0x10b76f18a74dbefaL   /*   12 */,    0xc6ccb6235ad1ab6aL   /*   13 */,
      0x13726121572fe2ffL   /*   14 */,    0x1a488c6f199d921eL   /*   15 */,
      0x4bc9f9f4da0007caL   /*   16 */,    0x26f5e6f6e85241c7L   /*   17 */,
      0x859079dbea5947b6L   /*   18 */,    0x4f1885c5c99e8c92L   /*   19 */,
      0xd78e761ea96f864bL   /*   20 */,    0x8e36428c52b5c17dL   /*   21 */,
      0x69cf6827373063c1L   /*   22 */,    0xb607c93d9bb4c56eL   /*   23 */,
      0x7d820e760e76b5eaL   /*   24 */,    0x645c9cc6f07fdc42L   /*   25 */,
      0xbf38a078243342e0L   /*   26 */,    0x5f6b343c9d2e7d04L   /*   27 */,
      0xf2c28aeb600b0ec6L   /*   28 */,    0x6c0ed85f7254bcacL   /*   29 */,
      0x71592281a4db4fe5L   /*   30 */,    0x1967fa69ce0fed9fL   /*   31 */,
      0xfd5293f8b96545dbL   /*   32 */,    0xc879e9d7f2a7600bL   /*   33 */,
      0x860248920193194eL   /*   34 */,    0xa4f9533b2d9cc0b3L   /*   35 */,
      0x9053836c15957613L   /*   36 */,    0xdb6dcf8afc357bf1L   /*   37 */,
      0x18beea7a7a370f57L   /*   38 */,    0x037117ca50b99066L   /*   39 */,
      0x6ab30a9774424a35L   /*   40 */,    0xf4e92f02e325249bL   /*   41 */,
      0x7739db07061ccae1L   /*   42 */,    0xd8f3b49ceca42a05L   /*   43 */,
      0xbd56be3f51382f73L   /*   44 */,    0x45faed5843b0bb28L   /*   45 */,
      0x1c813d5c11bf1f83L   /*   46 */,    0x8af0e4b6d75fa169L   /*   47 */,
      0x33ee18a487ad9999L   /*   48 */,    0x3c26e8eab1c94410L   /*   49 */,
      0xb510102bc0a822f9L   /*   50 */,    0x141eef310ce6123bL   /*   51 */,
      0xfc65b90059ddb154L   /*   52 */,    0xe0158640c5e0e607L   /*   53 */,
      0x884e079826c3a3cfL   /*   54 */,    0x930d0d9523c535fdL   /*   55 */,
      0x35638d754e9a2b00L   /*   56 */,    0x4085fccf40469dd5L   /*   57 */,
      0xc4b17ad28be23a4cL   /*   58 */,    0xcab2f0fc6a3e6a2eL   /*   59 */,
      0x2860971a6b943fcdL   /*   60 */,    0x3dde6ee212e30446L   /*   61 */,
      0x6222f32ae01765aeL   /*   62 */,    0x5d550bb5478308feL   /*   63 */,
      0xa9efa98da0eda22aL   /*   64 */,    0xc351a71686c40da7L   /*   65 */,
      0x1105586d9c867c84L   /*   66 */,    0xdcffee85fda22853L   /*   67 */,
      0xccfbd0262c5eef76L   /*   68 */,    0xbaf294cb8990d201L   /*   69 */,
      0xe69464f52afad975L   /*   70 */,    0x94b013afdf133e14L   /*   71 */,
      0x06a7d1a32823c958L   /*   72 */,    0x6f95fe5130f61119L   /*   73 */,
      0xd92ab34e462c06c0L   /*   74 */,    0xed7bde33887c71d2L   /*   75 */,
      0x79746d6e6518393eL   /*   76 */,    0x5ba419385d713329L   /*   77 */,
      0x7c1ba6b948a97564L   /*   78 */,    0x31987c197bfdac67L   /*   79 */,
      0xde6c23c44b053d02L   /*   80 */,    0x581c49fed002d64dL   /*   81 */,
      0xdd474d6338261571L   /*   82 */,    0xaa4546c3e473d062L   /*   83 */,
      0x928fce349455f860L   /*   84 */,    0x48161bbacaab94d9L   /*   85 */,
      0x63912430770e6f68L   /*   86 */,    0x6ec8a5e602c6641cL   /*   87 */,
      0x87282515337ddd2bL   /*   88 */,    0x2cda6b42034b701bL   /*   89 */,
      0xb03d37c181cb096dL   /*   90 */,    0xe108438266c71c6fL   /*   91 */,
      0x2b3180c7eb51b255L   /*   92 */,    0xdf92b82f96c08bbcL   /*   93 */,
      0x5c68c8c0a632f3baL   /*   94 */,    0x5504cc861c3d0556L   /*   95 */,
      0xabbfa4e55fb26b8fL   /*   96 */,    0x41848b0ab3baceb4L   /*   97 */,
      0xb334a273aa445d32L   /*   98 */,    0xbca696f0a85ad881L   /*   99 */,
      0x24f6ec65b528d56cL   /*  100 */,    0x0ce1512e90f4524aL   /*  101 */,
      0x4e9dd79d5506d35aL   /*  102 */,    0x258905fac6ce9779L   /*  103 */,
      0x2019295b3e109b33L   /*  104 */,    0xf8a9478b73a054ccL   /*  105 */,
      0x2924f2f934417eb0L   /*  106 */,    0x3993357d536d1bc4L   /*  107 */,
      0x38a81ac21db6ff8bL   /*  108 */,    0x47c4fbf17d6016bfL   /*  109 */,
      0x1e0faadd7667e3f5L   /*  110 */,    0x7abcff62938beb96L   /*  111 */,
      0xa78dad948fc179c9L   /*  112 */,    0x8f1f98b72911e50dL   /*  113 */,
      0x61e48eae27121a91L   /*  114 */,    0x4d62f7ad31859808L   /*  115 */,
      0xeceba345ef5ceaebL   /*  116 */,    0xf5ceb25ebc9684ceL   /*  117 */,
      0xf633e20cb7f76221L   /*  118 */,    0xa32cdf06ab8293e4L   /*  119 */,
      0x985a202ca5ee2ca4L   /*  120 */,    0xcf0b8447cc8a8fb1L   /*  121 */,
      0x9f765244979859a3L   /*  122 */,    0xa8d516b1a1240017L   /*  123 */,
      0x0bd7ba3ebb5dc726L   /*  124 */,    0xe54bca55b86adb39L   /*  125 */,
      0x1d7a3afd6c478063L   /*  126 */,    0x519ec608e7669eddL   /*  127 */,
      0x0e5715a2d149aa23L   /*  128 */,    0x177d4571848ff194L   /*  129 */,
      0xeeb55f3241014c22L   /*  130 */,    0x0f5e5ca13a6e2ec2L   /*  131 */,
      0x8029927b75f5c361L   /*  132 */,    0xad139fabc3d6e436L   /*  133 */,
      0x0d5df1a94ccf402fL   /*  134 */,    0x3e8bd948bea5dfc8L   /*  135 */,
      0xa5a0d357bd3ff77eL   /*  136 */,    0xa2d12e251f74f645L   /*  137 */,
      0x66fd9e525e81a082L   /*  138 */,    0x2e0c90ce7f687a49L   /*  139 */,
      0xc2e8bcbeba973bc5L   /*  140 */,    0x000001bce509745fL   /*  141 */,
      0x423777bbe6dab3d6L   /*  142 */,    0xd1661c7eaef06eb5L   /*  143 */,
      0xa1781f354daacfd8L   /*  144 */,    0x2d11284a2b16affcL   /*  145 */,
      0xf1fc4f67fa891d1fL   /*  146 */,    0x73ecc25dcb920adaL   /*  147 */,
      0xae610c22c2a12651L   /*  148 */,    0x96e0a810d356b78aL   /*  149 */,
      0x5a9a381f2fe7870fL   /*  150 */,    0xd5ad62ede94e5530L   /*  151 */,
      0xd225e5e8368d1427L   /*  152 */,    0x65977b70c7af4631L   /*  153 */,
      0x99f889b2de39d74fL   /*  154 */,    0x233f30bf54e1d143L   /*  155 */,
      0x9a9675d3d9a63c97L   /*  156 */,    0x5470554ff334f9a8L   /*  157 */,
      0x166acb744a4f5688L   /*  158 */,    0x70c74caab2e4aeadL   /*  159 */,
      0xf0d091646f294d12L   /*  160 */,    0x57b82a89684031d1L   /*  161 */,
      0xefd95a5a61be0b6bL   /*  162 */,    0x2fbd12e969f2f29aL   /*  163 */,
      0x9bd37013feff9fe8L   /*  164 */,    0x3f9b0404d6085a06L   /*  165 */,
      0x4940c1f3166cfe15L   /*  166 */,    0x09542c4dcdf3defbL   /*  167 */,
      0xb4c5218385cd5ce3L   /*  168 */,    0xc935b7dc4462a641L   /*  169 */,
      0x3417f8a68ed3b63fL   /*  170 */,    0xb80959295b215b40L   /*  171 */,
      0xf99cdaef3b8c8572L   /*  172 */,    0x018c0614f8fcb95dL   /*  173 */,
      0x1b14accd1a3acdf3L   /*  174 */,    0x84d471f200bb732dL   /*  175 */,
      0xc1a3110e95e8da16L   /*  176 */,    0x430a7220bf1a82b8L   /*  177 */,
      0xb77e090d39df210eL   /*  178 */,    0x5ef4bd9f3cd05e9dL   /*  179 */,
      0x9d4ff6da7e57a444L   /*  180 */,    0xda1d60e183d4a5f8L   /*  181 */,
      0xb287c38417998e47L   /*  182 */,    0xfe3edc121bb31886L   /*  183 */,
      0xc7fe3ccc980ccbefL   /*  184 */,    0xe46fb590189bfd03L   /*  185 */,
      0x3732fd469a4c57dcL   /*  186 */,    0x7ef700a07cf1ad65L   /*  187 */,
      0x59c64468a31d8859L   /*  188 */,    0x762fb0b4d45b61f6L   /*  189 */,
      0x155baed099047718L   /*  190 */,    0x68755e4c3d50baa6L   /*  191 */,
      0xe9214e7f22d8b4dfL   /*  192 */,    0x2addbf532eac95f4L   /*  193 */,
      0x32ae3909b4bd0109L   /*  194 */,    0x834df537b08e3450L   /*  195 */,
      0xfa209da84220728dL   /*  196 */,    0x9e691d9b9efe23f7L   /*  197 */,
      0x0446d288c4ae8d7fL   /*  198 */,    0x7b4cc524e169785bL   /*  199 */,
      0x21d87f0135ca1385L   /*  200 */,    0xcebb400f137b8aa5L   /*  201 */,
      0x272e2b66580796beL   /*  202 */,    0x3612264125c2b0deL   /*  203 */,
      0x057702bdad1efbb2L   /*  204 */,    0xd4babb8eacf84be9L   /*  205 */,
      0x91583139641bc67bL   /*  206 */,    0x8bdc2de08036e024L   /*  207 */,
      0x603c8156f49f68edL   /*  208 */,    0xf7d236f7dbef5111L   /*  209 */,
      0x9727c4598ad21e80L   /*  210 */,    0xa08a0896670a5fd7L   /*  211 */,
      0xcb4a8f4309eba9cbL   /*  212 */,    0x81af564b0f7036a1L   /*  213 */,
      0xc0b99aa778199abdL   /*  214 */,    0x959f1ec83fc8e952L   /*  215 */,
      0x8c505077794a81b9L   /*  216 */,    0x3acaaf8f056338f0L   /*  217 */,
      0x07b43f50627a6778L   /*  218 */,    0x4a44ab49f5eccc77L   /*  219 */,
      0x3bc3d6e4b679ee98L   /*  220 */,    0x9cc0d4d1cf14108cL   /*  221 */,
      0x4406c00b206bc8a0L   /*  222 */,    0x82a18854c8d72d89L   /*  223 */,
      0x67e366b35c3c432cL   /*  224 */,    0xb923dd61102b37f2L   /*  225 */,
      0x56ab2779d884271dL   /*  226 */,    0xbe83e1b0ff1525afL   /*  227 */,
      0xfb7c65d4217e49a9L   /*  228 */,    0x6bdbe0e76d48e7d4L   /*  229 */,
      0x08df828745d9179eL   /*  230 */,    0x22ea6a9add53bd34L   /*  231 */,
      0xe36e141c5622200aL   /*  232 */,    0x7f805d1b8cb750eeL   /*  233 */,
      0xafe5c7a59f58e837L   /*  234 */,    0xe27f996a4fb1c23cL   /*  235 */,
      0xd3867dfb0775f0d0L   /*  236 */,    0xd0e673de6e88891aL   /*  237 */,
      0x123aeb9eafb86c25L   /*  238 */,    0x30f1d5d5c145b895L   /*  239 */,
      0xbb434a2dee7269e7L   /*  240 */,    0x78cb67ecf931fa38L   /*  241 */,
      0xf33b0372323bbf9cL   /*  242 */,    0x52d66336fb279c74L   /*  243 */,
      0x505f33ac0afb4eaaL   /*  244 */,    0xe8a5cd99a2cce187L   /*  245 */,
      0x534974801e2d30bbL   /*  246 */,    0x8d2d5711d5876d90L   /*  247 */,
      0x1f1a412891bc038eL   /*  248 */,    0xd6e2e71d82e56648L   /*  249 */,
      0x74036c3a497732b7L   /*  250 */,    0x89b67ed96361f5abL   /*  251 */,
      0xffed95d8f1ea02a2L   /*  252 */,    0xe72b3bd61464d43dL   /*  253 */,
      0xa6300f170bdc4820L   /*  254 */,    0xebc18760ed78a77aL   /*  255 */
      };

   /** The second S-Box. */
   private static long[] TABLE2 = new long[] {
      0xe6a6be5a05a12138L   /*  256 */,    0xb5a122a5b4f87c98L   /*  257 */,
      0x563c6089140b6990L   /*  258 */,    0x4c46cb2e391f5dd5L   /*  259 */,
      0xd932addbc9b79434L   /*  260 */,    0x08ea70e42015aff5L   /*  261 */,
      0xd765a6673e478cf1L   /*  262 */,    0xc4fb757eab278d99L   /*  263 */,
      0xdf11c6862d6e0692L   /*  264 */,    0xddeb84f10d7f3b16L   /*  265 */,
      0x6f2ef604a665ea04L   /*  266 */,    0x4a8e0f0ff0e0dfb3L   /*  267 */,
      0xa5edeef83dbcba51L   /*  268 */,    0xfc4f0a2a0ea4371eL   /*  269 */,
      0xe83e1da85cb38429L   /*  270 */,    0xdc8ff882ba1b1ce2L   /*  271 */,
      0xcd45505e8353e80dL   /*  272 */,    0x18d19a00d4db0717L   /*  273 */,
      0x34a0cfeda5f38101L   /*  274 */,    0x0be77e518887caf2L   /*  275 */,
      0x1e341438b3c45136L   /*  276 */,    0xe05797f49089ccf9L   /*  277 */,
      0xffd23f9df2591d14L   /*  278 */,    0x543dda228595c5cdL   /*  279 */,
      0x661f81fd99052a33L   /*  280 */,    0x8736e641db0f7b76L   /*  281 */,
      0x15227725418e5307L   /*  282 */,    0xe25f7f46162eb2faL   /*  283 */,
      0x48a8b2126c13d9feL   /*  284 */,    0xafdc541792e76eeaL   /*  285 */,
      0x03d912bfc6d1898fL   /*  286 */,    0x31b1aafa1b83f51bL   /*  287 */,
      0xf1ac2796e42ab7d9L   /*  288 */,    0x40a3a7d7fcd2ebacL   /*  289 */,
      0x1056136d0afbbcc5L   /*  290 */,    0x7889e1dd9a6d0c85L   /*  291 */,
      0xd33525782a7974aaL   /*  292 */,    0xa7e25d09078ac09bL   /*  293 */,
      0xbd4138b3eac6edd0L   /*  294 */,    0x920abfbe71eb9e70L   /*  295 */,
      0xa2a5d0f54fc2625cL   /*  296 */,    0xc054e36b0b1290a3L   /*  297 */,
      0xf6dd59ff62fe932bL   /*  298 */,    0x3537354511a8ac7dL   /*  299 */,
      0xca845e9172fadcd4L   /*  300 */,    0x84f82b60329d20dcL   /*  301 */,
      0x79c62ce1cd672f18L   /*  302 */,    0x8b09a2add124642cL   /*  303 */,
      0xd0c1e96a19d9e726L   /*  304 */,    0x5a786a9b4ba9500cL   /*  305 */,
      0x0e020336634c43f3L   /*  306 */,    0xc17b474aeb66d822L   /*  307 */,
      0x6a731ae3ec9baac2L   /*  308 */,    0x8226667ae0840258L   /*  309 */,
      0x67d4567691caeca5L   /*  310 */,    0x1d94155c4875adb5L   /*  311 */,
      0x6d00fd985b813fdfL   /*  312 */,    0x51286efcb774cd06L   /*  313 */,
      0x5e8834471fa744afL   /*  314 */,    0xf72ca0aee761ae2eL   /*  315 */,
      0xbe40e4cdaee8e09aL   /*  316 */,    0xe9970bbb5118f665L   /*  317 */,
      0x726e4beb33df1964L   /*  318 */,    0x703b000729199762L   /*  319 */,
      0x4631d816f5ef30a7L   /*  320 */,    0xb880b5b51504a6beL   /*  321 */,
      0x641793c37ed84b6cL   /*  322 */,    0x7b21ed77f6e97d96L   /*  323 */,
      0x776306312ef96b73L   /*  324 */,    0xae528948e86ff3f4L   /*  325 */,
      0x53dbd7f286a3f8f8L   /*  326 */,    0x16cadce74cfc1063L   /*  327 */,
      0x005c19bdfa52c6ddL   /*  328 */,    0x68868f5d64d46ad3L   /*  329 */,
      0x3a9d512ccf1e186aL   /*  330 */,    0x367e62c2385660aeL   /*  331 */,
      0xe359e7ea77dcb1d7L   /*  332 */,    0x526c0773749abe6eL   /*  333 */,
      0x735ae5f9d09f734bL   /*  334 */,    0x493fc7cc8a558ba8L   /*  335 */,
      0xb0b9c1533041ab45L   /*  336 */,    0x321958ba470a59bdL   /*  337 */,
      0x852db00b5f46c393L   /*  338 */,    0x91209b2bd336b0e5L   /*  339 */,
      0x6e604f7d659ef19fL   /*  340 */,    0xb99a8ae2782ccb24L   /*  341 */,
      0xccf52ab6c814c4c7L   /*  342 */,    0x4727d9afbe11727bL   /*  343 */,
      0x7e950d0c0121b34dL   /*  344 */,    0x756f435670ad471fL   /*  345 */,
      0xf5add442615a6849L   /*  346 */,    0x4e87e09980b9957aL   /*  347 */,
      0x2acfa1df50aee355L   /*  348 */,    0xd898263afd2fd556L   /*  349 */,
      0xc8f4924dd80c8fd6L   /*  350 */,    0xcf99ca3d754a173aL   /*  351 */,
      0xfe477bacaf91bf3cL   /*  352 */,    0xed5371f6d690c12dL   /*  353 */,
      0x831a5c285e687094L   /*  354 */,    0xc5d3c90a3708a0a4L   /*  355 */,
      0x0f7f903717d06580L   /*  356 */,    0x19f9bb13b8fdf27fL   /*  357 */,
      0xb1bd6f1b4d502843L   /*  358 */,    0x1c761ba38fff4012L   /*  359 */,
      0x0d1530c4e2e21f3bL   /*  360 */,    0x8943ce69a7372c8aL   /*  361 */,
      0xe5184e11feb5ce66L   /*  362 */,    0x618bdb80bd736621L   /*  363 */,
      0x7d29bad68b574d0bL   /*  364 */,    0x81bb613e25e6fe5bL   /*  365 */,
      0x071c9c10bc07913fL   /*  366 */,    0xc7beeb7909ac2d97L   /*  367 */,
      0xc3e58d353bc5d757L   /*  368 */,    0xeb017892f38f61e8L   /*  369 */,
      0xd4effb9c9b1cc21aL   /*  370 */,    0x99727d26f494f7abL   /*  371 */,
      0xa3e063a2956b3e03L   /*  372 */,    0x9d4a8b9a4aa09c30L   /*  373 */,
      0x3f6ab7d500090fb4L   /*  374 */,    0x9cc0f2a057268ac0L   /*  375 */,
      0x3dee9d2dedbf42d1L   /*  376 */,    0x330f49c87960a972L   /*  377 */,
      0xc6b2720287421b41L   /*  378 */,    0x0ac59ec07c00369cL   /*  379 */,
      0xef4eac49cb353425L   /*  380 */,    0xf450244eef0129d8L   /*  381 */,
      0x8acc46e5caf4deb6L   /*  382 */,    0x2ffeab63989263f7L   /*  383 */,
      0x8f7cb9fe5d7a4578L   /*  384 */,    0x5bd8f7644e634635L   /*  385 */,
      0x427a7315bf2dc900L   /*  386 */,    0x17d0c4aa2125261cL   /*  387 */,
      0x3992486c93518e50L   /*  388 */,    0xb4cbfee0a2d7d4c3L   /*  389 */,
      0x7c75d6202c5ddd8dL   /*  390 */,    0xdbc295d8e35b6c61L   /*  391 */,
      0x60b369d302032b19L   /*  392 */,    0xce42685fdce44132L   /*  393 */,
      0x06f3ddb9ddf65610L   /*  394 */,    0x8ea4d21db5e148f0L   /*  395 */,
      0x20b0fce62fcd496fL   /*  396 */,    0x2c1b912358b0ee31L   /*  397 */,
      0xb28317b818f5a308L   /*  398 */,    0xa89c1e189ca6d2cfL   /*  399 */,
      0x0c6b18576aaadbc8L   /*  400 */,    0xb65deaa91299fae3L   /*  401 */,
      0xfb2b794b7f1027e7L   /*  402 */,    0x04e4317f443b5bebL   /*  403 */,
      0x4b852d325939d0a6L   /*  404 */,    0xd5ae6beefb207ffcL   /*  405 */,
      0x309682b281c7d374L   /*  406 */,    0xbae309a194c3b475L   /*  407 */,
      0x8cc3f97b13b49f05L   /*  408 */,    0x98a9422ff8293967L   /*  409 */,
      0x244b16b01076ff7cL   /*  410 */,    0xf8bf571c663d67eeL   /*  411 */,
      0x1f0d6758eee30da1L   /*  412 */,    0xc9b611d97adeb9b7L   /*  413 */,
      0xb7afd5887b6c57a2L   /*  414 */,    0x6290ae846b984fe1L   /*  415 */,
      0x94df4cdeacc1a5fdL   /*  416 */,    0x058a5bd1c5483affL   /*  417 */,
      0x63166cc142ba3c37L   /*  418 */,    0x8db8526eb2f76f40L   /*  419 */,
      0xe10880036f0d6d4eL   /*  420 */,    0x9e0523c9971d311dL   /*  421 */,
      0x45ec2824cc7cd691L   /*  422 */,    0x575b8359e62382c9L   /*  423 */,
      0xfa9e400dc4889995L   /*  424 */,    0xd1823ecb45721568L   /*  425 */,
      0xdafd983b8206082fL   /*  426 */,    0xaa7d29082386a8cbL   /*  427 */,
      0x269fcd4403b87588L   /*  428 */,    0x1b91f5f728bdd1e0L   /*  429 */,
      0xe4669f39040201f6L   /*  430 */,    0x7a1d7c218cf04adeL   /*  431 */,
      0x65623c29d79ce5ceL   /*  432 */,    0x2368449096c00bb1L   /*  433 */,
      0xab9bf1879da503baL   /*  434 */,    0xbc23ecb1a458058eL   /*  435 */,
      0x9a58df01bb401eccL   /*  436 */,    0xa070e868a85f143dL   /*  437 */,
      0x4ff188307df2239eL   /*  438 */,    0x14d565b41a641183L   /*  439 */,
      0xee13337452701602L   /*  440 */,    0x950e3dcf3f285e09L   /*  441 */,
      0x59930254b9c80953L   /*  442 */,    0x3bf299408930da6dL   /*  443 */,
      0xa955943f53691387L   /*  444 */,    0xa15edecaa9cb8784L   /*  445 */,
      0x29142127352be9a0L   /*  446 */,    0x76f0371fff4e7afbL   /*  447 */,
      0x0239f450274f2228L   /*  448 */,    0xbb073af01d5e868bL   /*  449 */,
      0xbfc80571c10e96c1L   /*  450 */,    0xd267088568222e23L   /*  451 */,
      0x9671a3d48e80b5b0L   /*  452 */,    0x55b5d38ae193bb81L   /*  453 */,
      0x693ae2d0a18b04b8L   /*  454 */,    0x5c48b4ecadd5335fL   /*  455 */,
      0xfd743b194916a1caL   /*  456 */,    0x2577018134be98c4L   /*  457 */,
      0xe77987e83c54a4adL   /*  458 */,    0x28e11014da33e1b9L   /*  459 */,
      0x270cc59e226aa213L   /*  460 */,    0x71495f756d1a5f60L   /*  461 */,
      0x9be853fb60afef77L   /*  462 */,    0xadc786a7f7443dbfL   /*  463 */,
      0x0904456173b29a82L   /*  464 */,    0x58bc7a66c232bd5eL   /*  465 */,
      0xf306558c673ac8b2L   /*  466 */,    0x41f639c6b6c9772aL   /*  467 */,
      0x216defe99fda35daL   /*  468 */,    0x11640cc71c7be615L   /*  469 */,
      0x93c43694565c5527L   /*  470 */,    0xea038e6246777839L   /*  471 */,
      0xf9abf3ce5a3e2469L   /*  472 */,    0x741e768d0fd312d2L   /*  473 */,
      0x0144b883ced652c6L   /*  474 */,    0xc20b5a5ba33f8552L   /*  475 */,
      0x1ae69633c3435a9dL   /*  476 */,    0x97a28ca4088cfdecL   /*  477 */,
      0x8824a43c1e96f420L   /*  478 */,    0x37612fa66eeea746L   /*  479 */,
      0x6b4cb165f9cf0e5aL   /*  480 */,    0x43aa1c06a0abfb4aL   /*  481 */,
      0x7f4dc26ff162796bL   /*  482 */,    0x6cbacc8e54ed9b0fL   /*  483 */,
      0xa6b7ffefd2bb253eL   /*  484 */,    0x2e25bc95b0a29d4fL   /*  485 */,
      0x86d6a58bdef1388cL   /*  486 */,    0xded74ac576b6f054L   /*  487 */,
      0x8030bdbc2b45805dL   /*  488 */,    0x3c81af70e94d9289L   /*  489 */,
      0x3eff6dda9e3100dbL   /*  490 */,    0xb38dc39fdfcc8847L   /*  491 */,
      0x123885528d17b87eL   /*  492 */,    0xf2da0ed240b1b642L   /*  493 */,
      0x44cefadcd54bf9a9L   /*  494 */,    0x1312200e433c7ee6L   /*  495 */,
      0x9ffcc84f3a78c748L   /*  496 */,    0xf0cd1f72248576bbL   /*  497 */,
      0xec6974053638cfe4L   /*  498 */,    0x2ba7b67c0cec4e4cL   /*  499 */,
      0xac2f4df3e5ce32edL   /*  500 */,    0xcb33d14326ea4c11L   /*  501 */,
      0xa4e9044cc77e58bcL   /*  502 */,    0x5f513293d934fcefL   /*  503 */,
      0x5dc9645506e55444L   /*  504 */,    0x50de418f317de40aL   /*  505 */,
      0x388cb31a69dde259L   /*  506 */,    0x2db4a83455820a86L   /*  507 */,
      0x9010a91e84711ae9L   /*  508 */,    0x4df7f0b7b1498371L   /*  509 */,
      0xd62a2eabc0977179L   /*  510 */,    0x22fac097aa8d5c0eL   /*  511 */
      };

   /** The third S-Box. */
   private static long[] TABLE3 = new long[] {
      0xf49fcc2ff1daf39bL   /*  512 */,    0x487fd5c66ff29281L   /*  513 */,
      0xe8a30667fcdca83fL   /*  514 */,    0x2c9b4be3d2fcce63L   /*  515 */,
      0xda3ff74b93fbbbc2L   /*  516 */,    0x2fa165d2fe70ba66L   /*  517 */,
      0xa103e279970e93d4L   /*  518 */,    0xbecdec77b0e45e71L   /*  519 */,
      0xcfb41e723985e497L   /*  520 */,    0xb70aaa025ef75017L   /*  521 */,
      0xd42309f03840b8e0L   /*  522 */,    0x8efc1ad035898579L   /*  523 */,
      0x96c6920be2b2abc5L   /*  524 */,    0x66af4163375a9172L   /*  525 */,
      0x2174abdcca7127fbL   /*  526 */,    0xb33ccea64a72ff41L   /*  527 */,
      0xf04a4933083066a5L   /*  528 */,    0x8d970acdd7289af5L   /*  529 */,
      0x8f96e8e031c8c25eL   /*  530 */,    0xf3fec02276875d47L   /*  531 */,
      0xec7bf310056190ddL   /*  532 */,    0xf5adb0aebb0f1491L   /*  533 */,
      0x9b50f8850fd58892L   /*  534 */,    0x4975488358b74de8L   /*  535 */,
      0xa3354ff691531c61L   /*  536 */,    0x0702bbe481d2c6eeL   /*  537 */,
      0x89fb24057deded98L   /*  538 */,    0xac3075138596e902L   /*  539 */,
      0x1d2d3580172772edL   /*  540 */,    0xeb738fc28e6bc30dL   /*  541 */,
      0x5854ef8f63044326L   /*  542 */,    0x9e5c52325add3bbeL   /*  543 */,
      0x90aa53cf325c4623L   /*  544 */,    0xc1d24d51349dd067L   /*  545 */,
      0x2051cfeea69ea624L   /*  546 */,    0x13220f0a862e7e4fL   /*  547 */,
      0xce39399404e04864L   /*  548 */,    0xd9c42ca47086fcb7L   /*  549 */,
      0x685ad2238a03e7ccL   /*  550 */,    0x066484b2ab2ff1dbL   /*  551 */,
      0xfe9d5d70efbf79ecL   /*  552 */,    0x5b13b9dd9c481854L   /*  553 */,
      0x15f0d475ed1509adL   /*  554 */,    0x0bebcd060ec79851L   /*  555 */,
      0xd58c6791183ab7f8L   /*  556 */,    0xd1187c5052f3eee4L   /*  557 */,
      0xc95d1192e54e82ffL   /*  558 */,    0x86eea14cb9ac6ca2L   /*  559 */,
      0x3485beb153677d5dL   /*  560 */,    0xdd191d781f8c492aL   /*  561 */,
      0xf60866baa784ebf9L   /*  562 */,    0x518f643ba2d08c74L   /*  563 */,
      0x8852e956e1087c22L   /*  564 */,    0xa768cb8dc410ae8dL   /*  565 */,
      0x38047726bfec8e1aL   /*  566 */,    0xa67738b4cd3b45aaL   /*  567 */,
      0xad16691cec0dde19L   /*  568 */,    0xc6d4319380462e07L   /*  569 */,
      0xc5a5876d0ba61938L   /*  570 */,    0x16b9fa1fa58fd840L   /*  571 */,
      0x188ab1173ca74f18L   /*  572 */,    0xabda2f98c99c021fL   /*  573 */,
      0x3e0580ab134ae816L   /*  574 */,    0x5f3b05b773645abbL   /*  575 */,
      0x2501a2be5575f2f6L   /*  576 */,    0x1b2f74004e7e8ba9L   /*  577 */,
      0x1cd7580371e8d953L   /*  578 */,    0x7f6ed89562764e30L   /*  579 */,
      0xb15926ff596f003dL   /*  580 */,    0x9f65293da8c5d6b9L   /*  581 */,
      0x6ecef04dd690f84cL   /*  582 */,    0x4782275fff33af88L   /*  583 */,
      0xe41433083f820801L   /*  584 */,    0xfd0dfe409a1af9b5L   /*  585 */,
      0x4325a3342cdb396bL   /*  586 */,    0x8ae77e62b301b252L   /*  587 */,
      0xc36f9e9f6655615aL   /*  588 */,    0x85455a2d92d32c09L   /*  589 */,
      0xf2c7dea949477485L   /*  590 */,    0x63cfb4c133a39ebaL   /*  591 */,
      0x83b040cc6ebc5462L   /*  592 */,    0x3b9454c8fdb326b0L   /*  593 */,
      0x56f56a9e87ffd78cL   /*  594 */,    0x2dc2940d99f42bc6L   /*  595 */,
      0x98f7df096b096e2dL   /*  596 */,    0x19a6e01e3ad852bfL   /*  597 */,
      0x42a99ccbdbd4b40bL   /*  598 */,    0xa59998af45e9c559L   /*  599 */,
      0x366295e807d93186L   /*  600 */,    0x6b48181bfaa1f773L   /*  601 */,
      0x1fec57e2157a0a1dL   /*  602 */,    0x4667446af6201ad5L   /*  603 */,
      0xe615ebcacfb0f075L   /*  604 */,    0xb8f31f4f68290778L   /*  605 */,
      0x22713ed6ce22d11eL   /*  606 */,    0x3057c1a72ec3c93bL   /*  607 */,
      0xcb46acc37c3f1f2fL   /*  608 */,    0xdbb893fd02aaf50eL   /*  609 */,
      0x331fd92e600b9fcfL   /*  610 */,    0xa498f96148ea3ad6L   /*  611 */,
      0xa8d8426e8b6a83eaL   /*  612 */,    0xa089b274b7735cdcL   /*  613 */,
      0x87f6b3731e524a11L   /*  614 */,    0x118808e5cbc96749L   /*  615 */,
      0x9906e4c7b19bd394L   /*  616 */,    0xafed7f7e9b24a20cL   /*  617 */,
      0x6509eadeeb3644a7L   /*  618 */,    0x6c1ef1d3e8ef0edeL   /*  619 */,
      0xb9c97d43e9798fb4L   /*  620 */,    0xa2f2d784740c28a3L   /*  621 */,
      0x7b8496476197566fL   /*  622 */,    0x7a5be3e6b65f069dL   /*  623 */,
      0xf96330ed78be6f10L   /*  624 */,    0xeee60de77a076a15L   /*  625 */,
      0x2b4bee4aa08b9bd0L   /*  626 */,    0x6a56a63ec7b8894eL   /*  627 */,
      0x02121359ba34fef4L   /*  628 */,    0x4cbf99f8283703fcL   /*  629 */,
      0x398071350caf30c8L   /*  630 */,    0xd0a77a89f017687aL   /*  631 */,
      0xf1c1a9eb9e423569L   /*  632 */,    0x8c7976282dee8199L   /*  633 */,
      0x5d1737a5dd1f7abdL   /*  634 */,    0x4f53433c09a9fa80L   /*  635 */,
      0xfa8b0c53df7ca1d9L   /*  636 */,    0x3fd9dcbc886ccb77L   /*  637 */,
      0xc040917ca91b4720L   /*  638 */,    0x7dd00142f9d1dcdfL   /*  639 */,
      0x8476fc1d4f387b58L   /*  640 */,    0x23f8e7c5f3316503L   /*  641 */,
      0x032a2244e7e37339L   /*  642 */,    0x5c87a5d750f5a74bL   /*  643 */,
      0x082b4cc43698992eL   /*  644 */,    0xdf917becb858f63cL   /*  645 */,
      0x3270b8fc5bf86ddaL   /*  646 */,    0x10ae72bb29b5dd76L   /*  647 */,
      0x576ac94e7700362bL   /*  648 */,    0x1ad112dac61efb8fL   /*  649 */,
      0x691bc30ec5faa427L   /*  650 */,    0xff246311cc327143L   /*  651 */,
      0x3142368e30e53206L   /*  652 */,    0x71380e31e02ca396L   /*  653 */,
      0x958d5c960aad76f1L   /*  654 */,    0xf8d6f430c16da536L   /*  655 */,
      0xc8ffd13f1be7e1d2L   /*  656 */,    0x7578ae66004ddbe1L   /*  657 */,
      0x05833f01067be646L   /*  658 */,    0xbb34b5ad3bfe586dL   /*  659 */,
      0x095f34c9a12b97f0L   /*  660 */,    0x247ab64525d60ca8L   /*  661 */,
      0xdcdbc6f3017477d1L   /*  662 */,    0x4a2e14d4decad24dL   /*  663 */,
      0xbdb5e6d9be0a1eebL   /*  664 */,    0x2a7e70f7794301abL   /*  665 */,
      0xdef42d8a270540fdL   /*  666 */,    0x01078ec0a34c22c1L   /*  667 */,
      0xe5de511af4c16387L   /*  668 */,    0x7ebb3a52bd9a330aL   /*  669 */,
      0x77697857aa7d6435L   /*  670 */,    0x004e831603ae4c32L   /*  671 */,
      0xe7a21020ad78e312L   /*  672 */,    0x9d41a70c6ab420f2L   /*  673 */,
      0x28e06c18ea1141e6L   /*  674 */,    0xd2b28cbd984f6b28L   /*  675 */,
      0x26b75f6c446e9d83L   /*  676 */,    0xba47568c4d418d7fL   /*  677 */,
      0xd80badbfe6183d8eL   /*  678 */,    0x0e206d7f5f166044L   /*  679 */,
      0xe258a43911cbca3eL   /*  680 */,    0x723a1746b21dc0bcL   /*  681 */,
      0xc7caa854f5d7cdd3L   /*  682 */,    0x7cac32883d261d9cL   /*  683 */,
      0x7690c26423ba942cL   /*  684 */,    0x17e55524478042b8L   /*  685 */,
      0xe0be477656a2389fL   /*  686 */,    0x4d289b5e67ab2da0L   /*  687 */,
      0x44862b9c8fbbfd31L   /*  688 */,    0xb47cc8049d141365L   /*  689 */,
      0x822c1b362b91c793L   /*  690 */,    0x4eb14655fb13dfd8L   /*  691 */,
      0x1ecbba0714e2a97bL   /*  692 */,    0x6143459d5cde5f14L   /*  693 */,
      0x53a8fbf1d5f0ac89L   /*  694 */,    0x97ea04d81c5e5b00L   /*  695 */,
      0x622181a8d4fdb3f3L   /*  696 */,    0xe9bcd341572a1208L   /*  697 */,
      0x1411258643cce58aL   /*  698 */,    0x9144c5fea4c6e0a4L   /*  699 */,
      0x0d33d06565cf620fL   /*  700 */,    0x54a48d489f219ca1L   /*  701 */,
      0xc43e5eac6d63c821L   /*  702 */,    0xa9728b3a72770dafL   /*  703 */,
      0xd7934e7b20df87efL   /*  704 */,    0xe35503b61a3e86e5L   /*  705 */,
      0xcae321fbc819d504L   /*  706 */,    0x129a50b3ac60bfa6L   /*  707 */,
      0xcd5e68ea7e9fb6c3L   /*  708 */,    0xb01c90199483b1c7L   /*  709 */,
      0x3de93cd5c295376cL   /*  710 */,    0xaed52edf2ab9ad13L   /*  711 */,
      0x2e60f512c0a07884L   /*  712 */,    0xbc3d86a3e36210c9L   /*  713 */,
      0x35269d9b163951ceL   /*  714 */,    0x0c7d6e2ad0cdb5faL   /*  715 */,
      0x59e86297d87f5733L   /*  716 */,    0x298ef221898db0e7L   /*  717 */,
      0x55000029d1a5aa7eL   /*  718 */,    0x8bc08ae1b5061b45L   /*  719 */,
      0xc2c31c2b6c92703aL   /*  720 */,    0x94cc596baf25ef42L   /*  721 */,
      0x0a1d73db22540456L   /*  722 */,    0x04b6a0f9d9c4179aL   /*  723 */,
      0xeffdafa2ae3d3c60L   /*  724 */,    0xf7c8075bb49496c4L   /*  725 */,
      0x9cc5c7141d1cd4e3L   /*  726 */,    0x78bd1638218e5534L   /*  727 */,
      0xb2f11568f850246aL   /*  728 */,    0xedfabcfa9502bc29L   /*  729 */,
      0x796ce5f2da23051bL   /*  730 */,    0xaae128b0dc93537cL   /*  731 */,
      0x3a493da0ee4b29aeL   /*  732 */,    0xb5df6b2c416895d7L   /*  733 */,
      0xfcabbd25122d7f37L   /*  734 */,    0x70810b58105dc4b1L   /*  735 */,
      0xe10fdd37f7882a90L   /*  736 */,    0x524dcab5518a3f5cL   /*  737 */,
      0x3c9e85878451255bL   /*  738 */,    0x4029828119bd34e2L   /*  739 */,
      0x74a05b6f5d3ceccbL   /*  740 */,    0xb610021542e13ecaL   /*  741 */,
      0x0ff979d12f59e2acL   /*  742 */,    0x6037da27e4f9cc50L   /*  743 */,
      0x5e92975a0df1847dL   /*  744 */,    0xd66de190d3e623feL   /*  745 */,
      0x5032d6b87b568048L   /*  746 */,    0x9a36b7ce8235216eL   /*  747 */,
      0x80272a7a24f64b4aL   /*  748 */,    0x93efed8b8c6916f7L   /*  749 */,
      0x37ddbff44cce1555L   /*  750 */,    0x4b95db5d4b99bd25L   /*  751 */,
      0x92d3fda169812fc0L   /*  752 */,    0xfb1a4a9a90660bb6L   /*  753 */,
      0x730c196946a4b9b2L   /*  754 */,    0x81e289aa7f49da68L   /*  755 */,
      0x64669a0f83b1a05fL   /*  756 */,    0x27b3ff7d9644f48bL   /*  757 */,
      0xcc6b615c8db675b3L   /*  758 */,    0x674f20b9bcebbe95L   /*  759 */,
      0x6f31238275655982L   /*  760 */,    0x5ae488713e45cf05L   /*  761 */,
      0xbf619f9954c21157L   /*  762 */,    0xeabac46040a8eae9L   /*  763 */,
      0x454c6fe9f2c0c1cdL   /*  764 */,    0x419cf6496412691cL   /*  765 */,
      0xd3dc3bef265b0f70L   /*  766 */,    0x6d0e60f5c3578a9eL   /*  767 */
      };

   /** The fourth S-Box. */
   private static long[] TABLE4 = new long[] {
      0x5b0e608526323c55L   /*  768 */,    0x1a46c1a9fa1b59f5L   /*  769 */,
      0xa9e245a17c4c8ffaL   /*  770 */,    0x65ca5159db2955d7L   /*  771 */,
      0x05db0a76ce35afc2L   /*  772 */,    0x81eac77ea9113d45L   /*  773 */,
      0x528ef88ab6ac0a0dL   /*  774 */,    0xa09ea253597be3ffL   /*  775 */,
      0x430ddfb3ac48cd56L   /*  776 */,    0xc4b3a67af45ce46fL   /*  777 */,
      0x4ececfd8fbe2d05eL   /*  778 */,    0x3ef56f10b39935f0L   /*  779 */,
      0x0b22d6829cd619c6L   /*  780 */,    0x17fd460a74df2069L   /*  781 */,
      0x6cf8cc8e8510ed40L   /*  782 */,    0xd6c824bf3a6ecaa7L   /*  783 */,
      0x61243d581a817049L   /*  784 */,    0x048bacb6bbc163a2L   /*  785 */,
      0xd9a38ac27d44cc32L   /*  786 */,    0x7fddff5baaf410abL   /*  787 */,
      0xad6d495aa804824bL   /*  788 */,    0xe1a6a74f2d8c9f94L   /*  789 */,
      0xd4f7851235dee8e3L   /*  790 */,    0xfd4b7f886540d893L   /*  791 */,
      0x247c20042aa4bfdaL   /*  792 */,    0x096ea1c517d1327cL   /*  793 */,
      0xd56966b4361a6685L   /*  794 */,    0x277da5c31221057dL   /*  795 */,
      0x94d59893a43acff7L   /*  796 */,    0x64f0c51ccdc02281L   /*  797 */,
      0x3d33bcc4ff6189dbL   /*  798 */,    0xe005cb184ce66af1L   /*  799 */,
      0xff5ccd1d1db99beaL   /*  800 */,    0xb0b854a7fe42980fL   /*  801 */,
      0x7bd46a6a718d4b9fL   /*  802 */,    0xd10fa8cc22a5fd8cL   /*  803 */,
      0xd31484952be4bd31L   /*  804 */,    0xc7fa975fcb243847L   /*  805 */,
      0x4886ed1e5846c407L   /*  806 */,    0x28cddb791eb70b04L   /*  807 */,
      0xc2b00be2f573417fL   /*  808 */,    0x5c9590452180f877L   /*  809 */,
      0x7a6bddfff370eb00L   /*  810 */,    0xce509e38d6d9d6a4L   /*  811 */,
      0xebeb0f00647fa702L   /*  812 */,    0x1dcc06cf76606f06L   /*  813 */,
      0xe4d9f28ba286ff0aL   /*  814 */,    0xd85a305dc918c262L   /*  815 */,
      0x475b1d8732225f54L   /*  816 */,    0x2d4fb51668ccb5feL   /*  817 */,
      0xa679b9d9d72bba20L   /*  818 */,    0x53841c0d912d43a5L   /*  819 */,
      0x3b7eaa48bf12a4e8L   /*  820 */,    0x781e0e47f22f1ddfL   /*  821 */,
      0xeff20ce60ab50973L   /*  822 */,    0x20d261d19dffb742L   /*  823 */,
      0x16a12b03062a2e39L   /*  824 */,    0x1960eb2239650495L   /*  825 */,
      0x251c16fed50eb8b8L   /*  826 */,    0x9ac0c330f826016eL   /*  827 */,
      0xed152665953e7671L   /*  828 */,    0x02d63194a6369570L   /*  829 */,
      0x5074f08394b1c987L   /*  830 */,    0x70ba598c90b25ce1L   /*  831 */,
      0x794a15810b9742f6L   /*  832 */,    0x0d5925e9fcaf8c6cL   /*  833 */,
      0x3067716cd868744eL   /*  834 */,    0x910ab077e8d7731bL   /*  835 */,
      0x6a61bbdb5ac42f61L   /*  836 */,    0x93513efbf0851567L   /*  837 */,
      0xf494724b9e83e9d5L   /*  838 */,    0xe887e1985c09648dL   /*  839 */,
      0x34b1d3c675370cfdL   /*  840 */,    0xdc35e433bc0d255dL   /*  841 */,
      0xd0aab84234131be0L   /*  842 */,    0x08042a50b48b7eafL   /*  843 */,
      0x9997c4ee44a3ab35L   /*  844 */,    0x829a7b49201799d0L   /*  845 */,
      0x263b8307b7c54441L   /*  846 */,    0x752f95f4fd6a6ca6L   /*  847 */,
      0x927217402c08c6e5L   /*  848 */,    0x2a8ab754a795d9eeL   /*  849 */,
      0xa442f7552f72943dL   /*  850 */,    0x2c31334e19781208L   /*  851 */,
      0x4fa98d7ceaee6291L   /*  852 */,    0x55c3862f665db309L   /*  853 */,
      0xbd0610175d53b1f3L   /*  854 */,    0x46fe6cb840413f27L   /*  855 */,
      0x3fe03792df0cfa59L   /*  856 */,    0xcfe700372eb85e8fL   /*  857 */,
      0xa7be29e7adbce118L   /*  858 */,    0xe544ee5cde8431ddL   /*  859 */,
      0x8a781b1b41f1873eL   /*  860 */,    0xa5c94c78a0d2f0e7L   /*  861 */,
      0x39412e2877b60728L   /*  862 */,    0xa1265ef3afc9a62cL   /*  863 */,
      0xbcc2770c6a2506c5L   /*  864 */,    0x3ab66dd5dce1ce12L   /*  865 */,
      0xe65499d04a675b37L   /*  866 */,    0x7d8f523481bfd216L   /*  867 */,
      0x0f6f64fcec15f389L   /*  868 */,    0x74efbe618b5b13c8L   /*  869 */,
      0xacdc82b714273e1dL   /*  870 */,    0xdd40bfe003199d17L   /*  871 */,
      0x37e99257e7e061f8L   /*  872 */,    0xfa52626904775aaaL   /*  873 */,
      0x8bbbf63a463d56f9L   /*  874 */,    0xf0013f1543a26e64L   /*  875 */,
      0xa8307e9f879ec898L   /*  876 */,    0xcc4c27a4150177ccL   /*  877 */,
      0x1b432f2cca1d3348L   /*  878 */,    0xde1d1f8f9f6fa013L   /*  879 */,
      0x606602a047a7ddd6L   /*  880 */,    0xd237ab64cc1cb2c7L   /*  881 */,
      0x9b938e7225fcd1d3L   /*  882 */,    0xec4e03708e0ff476L   /*  883 */,
      0xfeb2fbda3d03c12dL   /*  884 */,    0xae0bced2ee43889aL   /*  885 */,
      0x22cb8923ebfb4f43L   /*  886 */,    0x69360d013cf7396dL   /*  887 */,
      0x855e3602d2d4e022L   /*  888 */,    0x073805bad01f784cL   /*  889 */,
      0x33e17a133852f546L   /*  890 */,    0xdf4874058ac7b638L   /*  891 */,
      0xba92b29c678aa14aL   /*  892 */,    0x0ce89fc76cfaadcdL   /*  893 */,
      0x5f9d4e0908339e34L   /*  894 */,    0xf1afe9291f5923b9L   /*  895 */,
      0x6e3480f60f4a265fL   /*  896 */,    0xeebf3a2ab29b841cL   /*  897 */,
      0xe21938a88f91b4adL   /*  898 */,    0x57dfeff845c6d3c3L   /*  899 */,
      0x2f006b0bf62caaf2L   /*  900 */,    0x62f479ef6f75ee78L   /*  901 */,
      0x11a55ad41c8916a9L   /*  902 */,    0xf229d29084fed453L   /*  903 */,
      0x42f1c27b16b000e6L   /*  904 */,    0x2b1f76749823c074L   /*  905 */,
      0x4b76eca3c2745360L   /*  906 */,    0x8c98f463b91691bdL   /*  907 */,
      0x14bcc93cf1ade66aL   /*  908 */,    0x8885213e6d458397L   /*  909 */,
      0x8e177df0274d4711L   /*  910 */,    0xb49b73b5503f2951L   /*  911 */,
      0x10168168c3f96b6bL   /*  912 */,    0x0e3d963b63cab0aeL   /*  913 */,
      0x8dfc4b5655a1db14L   /*  914 */,    0xf789f1356e14de5cL   /*  915 */,
      0x683e68af4e51dac1L   /*  916 */,    0xc9a84f9d8d4b0fd9L   /*  917 */,
      0x3691e03f52a0f9d1L   /*  918 */,    0x5ed86e46e1878e80L   /*  919 */,
      0x3c711a0e99d07150L   /*  920 */,    0x5a0865b20c4e9310L   /*  921 */,
      0x56fbfc1fe4f0682eL   /*  922 */,    0xea8d5de3105edf9bL   /*  923 */,
      0x71abfdb12379187aL   /*  924 */,    0x2eb99de1bee77b9cL   /*  925 */,
      0x21ecc0ea33cf4523L   /*  926 */,    0x59a4d7521805c7a1L   /*  927 */,
      0x3896f5eb56ae7c72L   /*  928 */,    0xaa638f3db18f75dcL   /*  929 */,
      0x9f39358dabe9808eL   /*  930 */,    0xb7defa91c00b72acL   /*  931 */,
      0x6b5541fd62492d92L   /*  932 */,    0x6dc6dee8f92e4d5bL   /*  933 */,
      0x353f57abc4beea7eL   /*  934 */,    0x735769d6da5690ceL   /*  935 */,
      0x0a234aa642391484L   /*  936 */,    0xf6f9508028f80d9dL   /*  937 */,
      0xb8e319a27ab3f215L   /*  938 */,    0x31ad9c1151341a4dL   /*  939 */,
      0x773c22a57bef5805L   /*  940 */,    0x45c7561a07968633L   /*  941 */,
      0xf913da9e249dbe36L   /*  942 */,    0xda652d9b78a64c68L   /*  943 */,
      0x4c27a97f3bc334efL   /*  944 */,    0x76621220e66b17f4L   /*  945 */,
      0x967743899acd7d0bL   /*  946 */,    0xf3ee5bcae0ed6782L   /*  947 */,
      0x409f753600c879fcL   /*  948 */,    0x06d09a39b5926db6L   /*  949 */,
      0x6f83aeb0317ac588L   /*  950 */,    0x01e6ca4a86381f21L   /*  951 */,
      0x66ff3462d19f3025L   /*  952 */,    0x72207c24ddfd3bfbL   /*  953 */,
      0x4af6b6d3e2ece2ebL   /*  954 */,    0x9c994dbec7ea08deL   /*  955 */,
      0x49ace597b09a8bc4L   /*  956 */,    0xb38c4766cf0797baL   /*  957 */,
      0x131b9373c57c2a75L   /*  958 */,    0xb1822cce61931e58L   /*  959 */,
      0x9d7555b909ba1c0cL   /*  960 */,    0x127fafdd937d11d2L   /*  961 */,
      0x29da3badc66d92e4L   /*  962 */,    0xa2c1d57154c2ecbcL   /*  963 */,
      0x58c5134d82f6fe24L   /*  964 */,    0x1c3ae3515b62274fL   /*  965 */,
      0xe907c82e01cb8126L   /*  966 */,    0xf8ed091913e37fcbL   /*  967 */,
      0x3249d8f9c80046c9L   /*  968 */,    0x80cf9bede388fb63L   /*  969 */,
      0x1881539a116cf19eL   /*  970 */,    0x5103f3f76bd52457L   /*  971 */,
      0x15b7e6f5ae47f7a8L   /*  972 */,    0xdbd7c6ded47e9ccfL   /*  973 */,
      0x44e55c410228bb1aL   /*  974 */,    0xb647d4255edb4e99L   /*  975 */,
      0x5d11882bb8aafc30L   /*  976 */,    0xf5098bbb29d3212aL   /*  977 */,
      0x8fb5ea14e90296b3L   /*  978 */,    0x677b942157dd025aL   /*  979 */,
      0xfb58e7c0a390acb5L   /*  980 */,    0x89d3674c83bd4a01L   /*  981 */,
      0x9e2da4df4bf3b93bL   /*  982 */,    0xfcc41e328cab4829L   /*  983 */,
      0x03f38c96ba582c52L   /*  984 */,    0xcad1bdbd7fd85db2L   /*  985 */,
      0xbbb442c16082ae83L   /*  986 */,    0xb95fe86ba5da9ab0L   /*  987 */,
      0xb22e04673771a93fL   /*  988 */,    0x845358c9493152d8L   /*  989 */,
      0xbe2a488697b4541eL   /*  990 */,    0x95a2dc2dd38e6966L   /*  991 */,
      0xc02c11ac923c852bL   /*  992 */,    0x2388b1990df2a87bL   /*  993 */,
      0x7c8008fa1b4f37beL   /*  994 */,    0x1f70d0c84d54e503L   /*  995 */,
      0x5490adec7ece57d4L   /*  996 */,    0x002b3c27d9063a3aL   /*  997 */,
      0x7eaea3848030a2bfL   /*  998 */,    0xc602326ded2003c0L   /*  999 */,
      0x83a7287d69a94086L   /* 1000 */,    0xc57a5fcb30f57a8aL   /* 1001 */,
      0xb56844e479ebe779L   /* 1002 */,    0xa373b40f05dcbce9L   /* 1003 */,
      0xd71a786e88570ee2L   /* 1004 */,    0x879cbacdbde8f6a0L   /* 1005 */,
      0x976ad1bcc164a32fL   /* 1006 */,    0xab21e25e9666d78bL   /* 1007 */,
      0x901063aae5e5c33cL   /* 1008 */,    0x9818b34448698d90L   /* 1009 */,
      0xe36487ae3e1e8abbL   /* 1010 */,    0xafbdf931893bdcb4L   /* 1011 */,
      0x6345a0dc5fbbd519L   /* 1012 */,    0x8628fe269b9465caL   /* 1013 */,
      0x1e5d01603f9c51ecL   /* 1014 */,    0x4de44006a15049b7L   /* 1015 */,
      0xbf6c70e5f776cbb1L   /* 1016 */,    0x411218f2ef552bedL   /* 1017 */,
      0xcb0c0708705a36a3L   /* 1018 */,    0xe74d14754f986044L   /* 1019 */,
      0xcd56d9430ea8280eL   /* 1020 */,    0xc12591d7535f5065L   /* 1021 */,
      0xc83223f1720aef96L   /* 1022 */,    0xc3a0396f7363a51fL   /* 1023 */
      };

   /** The name of this message digest. */
   @SuppressWarnings("nls")
   public static final String NAME = "Tiger";

   /** The length in bytes of the digest. */
   public static final int HASH_LEN = 24;

   /** The length in bytes of a block. */
   public static final int BUFFER_LEN = 64;


//----------------------------
// Instance variables
//----------------------------

   /** The 1st element of the state "array". */
   protected long A;

   /** The 2nd element of the state "array". */
   protected long B;

   /** The 3rd element of the state "array". */
   protected long C;


//----------------------------
// Constructor
//----------------------------

   /**
    * Constructor.
    */
   public Tiger() {
      super(Tiger.NAME, Tiger.BUFFER_LEN, Tiger.HASH_LEN);
      this.coreInit();
      }


//----------------------------
// Tiger scrambling methods
//----------------------------

// very much inspired from the Cryptix one (cryptix.jce.provider.md.Tiger)
   private void roundABC(long x, long mul) {
      this.C ^= x;

      long c = this.C;
      this.A -= Tiger.TABLE1[(int)  (c         & 0xffL)] ^
                Tiger.TABLE2[(int) ((c >>> 16) & 0xffL)] ^
                Tiger.TABLE3[(int) ((c >>> 32) & 0xffL)] ^
                Tiger.TABLE4[(int) ((c >>> 48) & 0xffL)];
      this.B += Tiger.TABLE4[(int) ((c >>>  8) & 0xffL)] ^
                Tiger.TABLE3[(int) ((c >>> 24) & 0xffL)] ^
                Tiger.TABLE2[(int) ((c >>> 40) & 0xffL)] ^
                Tiger.TABLE1[(int) ((c >>> 56) & 0xffL)];
      this.B *= mul;
      }

   private void roundBCA(long x, long mul) {
      this.A ^= x;

      long a = this.A;
      this.B -= Tiger.TABLE1[(int)  (a         & 0xffL)] ^
                Tiger.TABLE2[(int) ((a >>> 16) & 0xffL)] ^
                Tiger.TABLE3[(int) ((a >>> 32) & 0xffL)] ^
                Tiger.TABLE4[(int) ((a >>> 48) & 0xffL)];
      this.C += Tiger.TABLE4[(int) ((a >>>  8) & 0xffL)] ^
                Tiger.TABLE3[(int) ((a >>> 24) & 0xffL)] ^
                Tiger.TABLE2[(int) ((a >>> 40) & 0xffL)] ^
                Tiger.TABLE1[(int) ((a >>> 56) & 0xffL)];
      this.C *= mul;

      }

   private void roundCAB(long x, long mul) {
      this.B ^= x;

      long b = this.B;
      this.C -= Tiger.TABLE1[(int)  (b         & 0xffL)] ^
                Tiger.TABLE2[(int) ((b >>> 16) & 0xffL)] ^
                Tiger.TABLE3[(int) ((b >>> 32) & 0xffL)] ^
                Tiger.TABLE4[(int) ((b >>> 48) & 0xffL)];
      this.A += Tiger.TABLE4[(int) ((b >>>  8) & 0xffL)] ^
                Tiger.TABLE3[(int) ((b >>> 24) & 0xffL)] ^
                Tiger.TABLE2[(int) ((b >>> 40) & 0xffL)] ^
                Tiger.TABLE1[(int) ((b >>> 56) & 0xffL)];
      this.A *= mul;
      }


//----------------------------
// Concrete core methods
//----------------------------

   @Override
   protected void coreTransform() {
      byte[] buffer = this.getBuffer();

      long x_0 = AbstractBlockMessageDigest.makeLong(buffer,  7,  6,  5,  4,  3,  2,  1,  0);
      long x_1 = AbstractBlockMessageDigest.makeLong(buffer, 15, 14, 13, 12, 11, 10,  9,  8);
      long x_2 = AbstractBlockMessageDigest.makeLong(buffer, 23, 22, 21, 20, 19, 18, 17, 16);
      long x_3 = AbstractBlockMessageDigest.makeLong(buffer, 31, 30, 29, 28, 27, 26, 25, 24);
      long x_4 = AbstractBlockMessageDigest.makeLong(buffer, 39, 38, 37, 36, 35, 34, 33, 32);
      long x_5 = AbstractBlockMessageDigest.makeLong(buffer, 47, 46, 45, 44, 43, 42, 41, 40);
      long x_6 = AbstractBlockMessageDigest.makeLong(buffer, 55, 54, 53, 52, 51, 50, 49, 48);
      long x_7 = AbstractBlockMessageDigest.makeLong(buffer, 63, 62, 61, 60, 59, 58, 57, 56);

//      long x_0 = AbstractBlockMessageDigest.makeLong(buffer,  0,  1,  2,  3,  4,  5,  6,  7);
//      long x_1 = AbstractBlockMessageDigest.makeLong(buffer,  8,  9, 10, 11, 12, 13, 14, 15);
//      long x_2 = AbstractBlockMessageDigest.makeLong(buffer, 16, 17, 18, 19, 20, 21, 22, 23);
//      long x_3 = AbstractBlockMessageDigest.makeLong(buffer, 24, 25, 26, 27, 28, 29, 30, 31);
//      long x_4 = AbstractBlockMessageDigest.makeLong(buffer, 32, 33, 34, 35, 36, 37, 38, 39);
//      long x_5 = AbstractBlockMessageDigest.makeLong(buffer, 40, 41, 42, 43, 44, 45, 46, 47);
//      long x_6 = AbstractBlockMessageDigest.makeLong(buffer, 48, 49, 50, 51, 52, 53, 54, 55);
//      long x_7 = AbstractBlockMessageDigest.makeLong(buffer, 56, 57, 58, 59, 60, 61, 62, 63);

      AbstractBlockMessageDigest.zeroize(buffer);

      long aa = this.A;
      long bb = this.B;
      long cc = this.C;

   // pass 1 with mul = 5
      this.roundABC(x_0, 5);
      this.roundBCA(x_1, 5);
      this.roundCAB(x_2, 5);
      this.roundABC(x_3, 5);
      this.roundBCA(x_4, 5);
      this.roundCAB(x_5, 5);
      this.roundABC(x_6, 5);
      this.roundBCA(x_7, 5);
   // key schedule
      x_0 -= x_7 ^ 0xa5a5a5a5a5a5a5a5L;
      x_1 ^= x_0;
      x_2 += x_1;
      x_3 -= x_2 ^ ((~x_1) << 19);
      x_4 ^= x_3;
      x_5 += x_4;
      x_6 -= x_5 ^ ((~x_4) >>> 23);
      x_7 ^= x_6;
      x_0 += x_7;
      x_1 -= x_0 ^ ((~x_7) << 19);
      x_2 ^= x_1;
      x_3 += x_2;
      x_4 -= x_3 ^ ((~x_2) >>> 23);
      x_5 ^= x_4;
      x_6 += x_5;
      x_7 -= x_6 ^ 0x0123456789abcdefL;
   // pass 2 with mul = 7
      this.roundCAB(x_0, 7);
      this.roundABC(x_1, 7);
      this.roundBCA(x_2, 7);
      this.roundCAB(x_3, 7);
      this.roundABC(x_4, 7);
      this.roundBCA(x_5, 7);
      this.roundCAB(x_6, 7);
      this.roundABC(x_7, 7);
   // key schedule
      x_0 -= x_7 ^ 0xa5a5a5a5a5a5a5a5L;
      x_1 ^= x_0;
      x_2 += x_1;
      x_3 -= x_2 ^ ((~x_1) << 19);
      x_4 ^= x_3;
      x_5 += x_4;
      x_6 -= x_5 ^ ((~x_4) >>> 23);
      x_7 ^= x_6;
      x_0 += x_7;
      x_1 -= x_0 ^ ((~x_7) << 19);
      x_2 ^= x_1;
      x_3 += x_2;
      x_4 -= x_3 ^ ((~x_2) >>> 23);
      x_5 ^= x_4;
      x_6 += x_5;
      x_7 -= x_6 ^ 0x0123456789abcdefL;
   // pass 3 with mul = 9
      this.roundBCA(x_0, 9);
      this.roundCAB(x_1, 9);
      this.roundABC(x_2, 9);
      this.roundBCA(x_3, 9);
      this.roundCAB(x_4, 9);
      this.roundABC(x_5, 9);
      this.roundBCA(x_6, 9);
      this.roundCAB(x_7, 9);
   // feedforward
      this.A ^= aa;
      this.B -= bb;
      this.C += cc;
      }

   @Override
   protected void coreInit() {
   // load magic initialization constants
      this.A = 0x0123456789abcdefL;
      this.B = 0xfedcba9876543210L;
      this.C = 0xf096a5b4c3b2e187L;
      }

   @Override
   protected byte[] coreDoFinal() {
      long count = this.getCount();
      long bits = count * 8L;

      int index = (int) (count % Tiger.BUFFER_LEN);
      int padlen = (index < (Tiger.BUFFER_LEN - 8)) ? (Tiger.BUFFER_LEN - 8) - index : (2 * Tiger.BUFFER_LEN - 8) - index;
   // padding
      byte[] last = new byte[padlen + 8];
// BUG : figure out which constant to use, Mr. Anderson or Mr. Biham ?
/*
 * there is a contradiction between Mr. Anderson and Mr. Biham on the first
 * byte of padding, I put 0x80 because it is what is mentionned in the paper
 * and not what is in Mr. Biham reference implementation (but is in Mr. Anderson's).
 */
/*
 * Cryptix (www.crytix.org) and GnuPG (www.gnupg.org) use 0x01.
 */
      last[0] = (byte) 0x01;
//      last[0] = (byte) 0x80;
      padlen = AbstractBlockMessageDigest.breakLongLE(bits, last, padlen);

      this.engineUpdate(last, 0, padlen);

      byte[] digest = new byte[Tiger.HASH_LEN];
      AbstractBlockMessageDigest.breakLongLE(this.A, digest, 0);
      AbstractBlockMessageDigest.breakLongLE(this.B, digest, 8);
      AbstractBlockMessageDigest.breakLongLE(this.C, digest, 16);

      this.coreInit();

      return digest;
      }

   }

